package com.eischet.lookup.web;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

import static com.eischet.lookup.DateUtilities.formatDate;
import static com.eischet.lookup.DateUtilities.formatTimestamp;
import static com.eischet.lookup.Functional.ordered;

/**
 * Represents a Hit, or search result, in the Lookup web application.
 */
public class SearchResult {
    private final Document doc;
    private final LuceneQuery query;
    private final Set<String> types;
    private final Map<String, String> data;
    private final SearchableType type;

    /**
     * create a search result wrapper
     *
     * @param searchIndex       the index
     * @param doc               the document found by a Lucene query
     * @param query             the Lucene query that found said document
     */
    public SearchResult(SearchIndex searchIndex, Document doc, LuceneQuery query) {
        this.doc = doc;
        this.query = query;
        this.types = new HashSet<String>();
        for (Field field: doc.getFields("type")) {
            types.add(field.stringValue());
        }
        this.data = new HashMap<String, String>();
        for (Fieldable field: doc.getFields()) {
            data.put(field.name(), getField(field.name()));
        }
        type = searchIndex.getType(data.get("list"));
    }

    /**
     * @return the object's "list" type
     */
    public String getListType() {
        return data.get("list");
    }

    /**
     * @param key   a field key
     * @return      the field's String value, which <i>will never by null</i>
     */
    @NotNull
    public String getField(String key) {
        Field field = doc.getField(key);
        String value = field == null ? "" : field.stringValue();
        return value == null ? "" : value;
    }

    /**
     * @param key   a field key
     * @return      all fields for the key
     */
    public List<Field> getFields(String key) {
        Field[] fields = doc.getFields(key);
        return Arrays.asList(fields);
    }

    /**
     * @param key   a field key
     * @return      the field's String value, which <i>might be null</i>
     */
    @Nullable
    public String get(String key) {
        return data.get(key);
    }

    /**
     * @return all existing fields for the document, ordered alphabetically
     */
    public List<String> getKeys() {
        return ordered(data.keySet());
    }

    /**
     * @param key   a field key
     * @return      highlighted field data
     */
    public String highlight(String key) {
        return query.highlight(doc, key);
    }

    /**
     * @param key   a field key
     * @return      a formatted timestamp of the field's data
     */
    public String getTimestamp(String key) {
        return formatTimestamp(get(key));
    }

    /**
     * @param bodyKey   the body key for the link
     * @return          the link's body
     */
    public String getLink(String bodyKey) {
        return type.getLink(data, get(bodyKey));
    }
}
